from eventServer import eventServer
from collisionServer import collisionServer
from optionServer import OptionServer
from soundServer import sound
from textureServer import textureServer
import pygame
import sys
import time

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

class GameServer:
    def __init__(self):
        self.maxDTime = 1.0/60.0
        
        self.removeCache = []
        eventServer.register("update",self.update)
        
    def update(self, cmd, args):
        for name in self.removeCache:
            self.doRemoveObject(name)
        self.removeCache = []
        
    def removeObject(self, name):
        self.removeCache.append(name)
        
    def doRemoveObject(self, name):
        if self.hasObject(name):
            obj = self.objects.pop(name)
            obj.destroy()
            eventServer.unregisterObject(obj)
            return obj
        else:
            return None
        
    def run(self):
        self.objects = {}
        
        eventServer.register("shutdown",self.requestShutdown)
        
        self.optionServer = self.addObject("optionServer",OptionServer())
        
        if self.optionServer.hasVar("frameLimit"):
            self.frameLimit = self.optionServer.getVar("frameLimit")
        else:
            self.frameLimit = 60
        
        if self.optionServer.hasVar("screenw"):
            self.screenw = self.optionServer.getVar("screenw")
        else:
            self.screenw = 800
        if self.optionServer.hasVar("screenh"):
            self.screenh = self.optionServer.getVar("screenh")
        else:
            self.screenh = 600
            
        if self.optionServer.hasVar('textures'):
            textureServer.doTexturing = self.optionServer.getVar("textures")
            
        self.fullscreen = False
        if self.optionServer.hasVar('fullscreen') and self.optionServer.getVar("fullscreen"):
            self.fullscreen = True
        
        self.initGfx()
        self.initJoysticks()
        
        self.mainLoop()
        
    def startGame(self):
        from acce import Acce
        
        self.game = self.addObject("Acce",Acce())
        
        eventServer.pull("startAcce",{})
        
    def requestShutdown(self, cmd, args):
        self.shutdown = True
            
    def initGfx(self):
        pygame.init()
        glutInit(sys.argv)
        
        if self.fullscreen:
            flags = pygame.OPENGL | pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.FULLSCREEN
        else:
            flags = pygame.OPENGL | pygame.DOUBLEBUF | pygame.HWSURFACE
        self.screen = pygame.display.set_mode((self.screenw,self.screenh), flags)
        pygame.display.set_caption("ACCE")
        
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_TEXTURE_2D)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
        glClearColor(0,0,1,0)
        
    def initJoysticks(self):
        self.joystickCount = pygame.joystick.get_count()
        print "%d joysticks found" % self.joystickCount
        
        self.joysticks = []
        for i in range(self.joystickCount):
            joystick = pygame.joystick.Joystick(i)
            joystick.init()
            self.joysticks.append(joystick)
        
    def set3dProjection(self):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45.0,float(self.screenw)/float(self.screenh),1.0,500.0)
        
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        
    def set2dProjection(self):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluOrtho2D(0,self.screenw,0,self.screenh)
        
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslate(0,self.screenh,0)
        glScalef(1,-1,1)
        
    def mainLoop(self):
        self.shutdown = False
        
        startTime = ptime = time.time()
        renderStartTime = 0
        renderTime = 1.0 / float(self.frameLimit)
        frameCount = 0
        renderFrameCount = 0
        renderFrames = 0
        sumRenderFrameCount = 0
        
        self.startGame()
        
        while not self.shutdown:
            currentTime = time.time() - startTime
            dtime = currentTime - ptime
            ptime = currentTime
            
            if(dtime > self.maxDTime):
                #print " --- Max DTime Exceeded", self.maxDTime, dtime, dtime/self.maxDTime
                dtime = self.maxDTime
            if(dtime < 0):
                dtime = 0
            
            self.processInput()
            
            eventServer.pull("update",{"time":currentTime,"dtime":dtime})
            
            if currentTime - renderStartTime > renderTime:
                renderStartTime = currentTime
                sumRenderFrameCount += renderFrameCount
                renderFrameCount = 0
                renderFrames += 1
                self.render(currentTime, dtime)
            else:
                renderFrameCount += 1
                
            frameCount += 1
                        
        totalTime = time.time() - startTime
        fps = float(frameCount) / totalTime
        print "%d frames in %f seconds = %f fps" % (frameCount,totalTime,fps)
        
        aveRenderFrameCount = float(sumRenderFrameCount) / float(renderFrames)
        print "averaged %f update frames per render" % aveRenderFrameCount
        
        eventServer.pull("shutdownSingletons",{})
        
        print "shutting down gameServer"
        pygame.quit()
            
    def render(self, currentTime, dtime):
        self.preRender()
        self.set3dProjection()
        eventServer.pull("cameraRender",{"time":currentTime,"dtime":dtime})
        eventServer.pull("backgroundRender",{"time":currentTime,"dtime":dtime})
        eventServer.pull("preRender",{"time":currentTime,"dtime":dtime})
        eventServer.pull("render",{"time":currentTime,"dtime":dtime})
        eventServer.pull("postRender",{"time":currentTime,"dtime":dtime})
        self.set2dProjection()
        eventServer.pull("overlayRender",{"time":currentTime,"dtime":dtime})
        self.postRender()
            
    def processInput(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.shutdown = True
                
            elif event.type == pygame.KEYDOWN:
                if event.key < 256:
                    keyChar = chr(event.key)
                else:
                    keyChar = None
                
                mods = pygame.key.get_mods()
                shift = mods & pygame.KMOD_SHIFT != 0
                alt = mods & pygame.KMOD_ALT != 0
                ctrl = mods & pygame.KMOD_CTRL != 0
                    
                eventServer.pull("keyDown",{"key":event.key,"keyChar":keyChar,"shift":shift,"ctrl":ctrl,"alt":alt})
            
            elif event.type == pygame.KEYUP:
                if event.key < 256:
                    keyChar = chr(event.key)
                else:
                    keyChar = None
                    
                mods = pygame.key.get_mods()
                shift = mods & pygame.KMOD_SHIFT != 0
                alt = mods & pygame.KMOD_ALT != 0
                ctrl = mods & pygame.KMOD_CTRL != 0
                    
                eventServer.pull("keyUp",{"key":event.key,"keyChar":keyChar,"shift":shift,"ctrl":ctrl,"alt":alt})
                    
            elif event.type == pygame.MOUSEBUTTONDOWN:
                x,y = self.convertMouseCoord(pygame.mouse.get_pos())
                #print "mouse button down", event.button, x, y
                eventServer.pull("mouseButtonDown",{"button":event.button,"x":x,"y":y})
            
            elif event.type == pygame.MOUSEBUTTONUP:
                x,y = self.convertMouseCoord(pygame.mouse.get_pos())
                #print "mouse button up", event.button, x, y
                eventServer.pull("mouseButtonUp",{"button":event.button,"x":x,"y":y})
                
            elif event.type == pygame.MOUSEMOTION:
                x,y = self.convertMouseCoord(event.pos)
                dx,dy = self.convertMouseCoord(event.rel)
                eventServer.pull("mouseMotion",{"x":x,"y":y,"dx":dx,"dy":dy})
                
            elif event.type == pygame.JOYBUTTONDOWN:
                joy = event.joy
                button = event.button
                
                #print "joyButtonDown", joy, button
                
                eventServer.pull("joyButtonDown",{"joy":joy,"button":button})
                
            elif event.type == pygame.JOYBUTTONUP:
                joy = event.joy
                button = event.button
                
                #print "joyButtonUp", joy, button
                
                eventServer.pull("joyButtonUp",{"joy":joy,"button":button})
                
            elif event.type == pygame.JOYAXISMOTION:
                joy = event.joy
                axis = event.axis
                value = event.value
                
                #print "joyAxisMotion", joy, axis, value
                
                eventServer.pull("joyAxisMotion",{"joy":joy,"axis":axis,"value":value})
                
            #else:
            #    print "unknown event", event
                
    def convertMouseCoord(self, coord):
        return float(coord[0]) / self.screenw, float(coord[1]) / self.screenh
            
    def preRender(self):
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)
        
    def postRender(self):
        glFlush()
        pygame.display.flip()
        
    def addObject(self, name, obj):
        if self.hasObject(name):
            self.removeObject(name)
        self.objects[name] = obj
        obj.setVar("name",name)
        return obj
        
    def hasObject(self, name):
        return self.objects.has_key(name)
    
    def getObject(self, name):
        if self.hasObject(name):
            return self.objects[name]
        else:
            return None
        
    def makeObjectName(self, base = "obj"):
        #if not self.hasObject(base):
        #    return base
        count = 0
        name = "%s_%d" % (base,count)
        while self.hasObject(name):
            count += 1
            name = "%s_%d" % (base,count)
        return name

gameServer = GameServer()
gameServer.run()
